package top.kangyaocoding.ecommerce.controller;

import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import top.kangyaocoding.ecommerce.IUserBehaviorService;
import top.kangyaocoding.ecommerce.constants.Constants;
import top.kangyaocoding.ecommerce.exception.AppException;
import top.kangyaocoding.ecommerce.po.*;
import top.kangyaocoding.ecommerce.response.Response;
import top.kangyaocoding.ecommerce.utils.JwtUtil;

import java.util.List;

/**
 * 描述：用户行为控制层
 *
 * @author K·Herbert
 * @since 2025-02-16 下午4:47
 */
@Slf4j
@RestController
@RequestMapping("/userBehavior")
@CrossOrigin("*")
@RateLimiter(name = "userBehaviorController", fallbackMethod = "fallbackMethod")
public class UserBehaviorController {

    private final IUserBehaviorService userBehaviorService;
    private final JwtUtil jwtUtil;

    // 构造函数
    public UserBehaviorController(IUserBehaviorService userBehaviorService, JwtUtil jwtUtil) {
        this.userBehaviorService = userBehaviorService;
        this.jwtUtil = jwtUtil;
    }

    @GetMapping("/arppuDaily")
    public Response<List<ArppuDaily>> getAllArppuDaily(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllArppuDaily);
    }

    @GetMapping("/arpuDaily")
    public Response<List<ArpuDaily>> getAllArpuDaily(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllArpuDaily);
    }

    @GetMapping("/behaviorTypeWithHour")
    public Response<List<BehaviorTypeWithHour>> getAllBehaviorTypeWithHour(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllBehaviorTypeWithHour);
    }

    @GetMapping("/behaviorTypeWithHour1212")
    public Response<List<BehaviorTypeWithHour1212>> getAllBehaviorTypeWithHour1212(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllBehaviorTypeWithHour1212);
    }

    @GetMapping("/conversionPercentage")
    public Response<List<ConversionPercentage>> getAllConversionPercentage(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllConversionPercentage);
    }

    @GetMapping("/conversionPercentage1212")
    public Response<List<ConversionPercentage1212>> getAllConversionPercentage1212(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllConversionPercentage1212);
    }

    @GetMapping("/dataSummary")
    public Response<List<DataSummary>> getAllDataSummary(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllDataSummary);
    }

    @GetMapping("/orderRateDaily")
    public Response<List<OrderRateDaily>> getAllOrderRateDaily(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllOrderRateDaily);
    }

    @GetMapping("/pvDaily")
    public Response<List<PvDaily>> getAllPvDaily(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllPvDaily);
    }

    @GetMapping("/pvHourly")
    public Response<List<PvHourly>> getAllPvHourly(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllPvHourly);
    }

    @GetMapping("/pvHourly1212")
    public Response<List<PvHourly1212>> getAllPvHourly1212(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllPvHourly1212);
    }

    @GetMapping("/repeatBuyCycle")
    public Response<List<RepeatBuyCycle>> getAllRepeatBuyCycle(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllRepeatBuyCycle);
    }

    @GetMapping("/repeatBuyRatio")
    public Response<List<RepeatBuyRatio>> getAllRepeatBuyRatio(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllRepeatBuyRatio);
    }

    @GetMapping("/userBehaviorDistribution")
    public Response<List<UserBehaviorDistribution>> getAllUserBehaviorDistribution(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUserBehaviorDistribution);
    }

    @GetMapping("/userBuyCount")
    public Response<List<UserBuyCount>> getAllUserBuyCount(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUserBuyCount);
    }

    @GetMapping("/top50UserBuyCount")
    public Response<List<UserBuyCount>> getTop50UserBuyCount(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getTop50UserBuyCount);
    }

    @GetMapping("/userClusterFeatures")
    public Response<List<UserClusterFeatures>> getAllUserClusterFeatures(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUserClusterFeatures);
    }

    @GetMapping("/uvDaily")
    public Response<List<UvDaily>> getAllUvDaily(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUvDaily);
    }

    @GetMapping("/uvHourly")
    public Response<List<UvHourly>> getAllUvHourly(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUvHourly);
    }

    @GetMapping("/uvHourly1212")
    public Response<List<UvHourly1212>> getAllUvHourly1212(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllUvHourly1212);
    }

    @GetMapping("/PathConversionRate")
    public Response<List<PathConversionRate>> getAllPathConversionRate(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllPathConversionRate);
    }

    @GetMapping("/PathConversionRate1212")
    public Response<List<PathConversionRate1212>> getAllPathConversionRate1212(@RequestHeader("Authorization") String token) {
        return handleRequest(token, userBehaviorService::getAllPathConversionRate1212);
    }

    private <T> Response<List<T>> handleRequest(String token, DataFetcher<T> dataFetcher) {
        try {
            // 1. 验证Token
            if (!jwtUtil.validateToken(token)) {
                log.error("Token验证失败: {}", Constants.ErrorCode.TOKEN_ERROR.getInfo());
                return buildErrorResponse(Constants.ErrorCode.TOKEN_ERROR);
            }
            log.info("Token验证成功");
            // 2. 获取数据
            List<T> data = dataFetcher.fetch();

            // 3. 校验数据
            if (data == null || data.isEmpty()) {
                log.warn("未找到数据");
                return buildErrorResponse(Constants.ErrorCode.DATA_NOT_FOUND);
            }

            // 4. 成功响应
            return Response.<List<T>>builder()
                    .code(Constants.ErrorCode.SUCCESS.getCode())
                    .info(Constants.ErrorCode.SUCCESS.getInfo())
                    .data(data)
                    .build();

        } catch (Exception e) {
            log.error("系统异常: ", e);
            throw new AppException(
                    Constants.ErrorCode.UN_ERROR.getCode(),
                    Constants.ErrorCode.UN_ERROR.getInfo(),
                    e
            );
        }
    }

    private <T> Response<List<T>> buildErrorResponse(Constants.ErrorCode errorCode) {
        return Response.<List<T>>builder()
                .code(errorCode.getCode())
                .info(errorCode.getInfo())
                .data(null)
                .build();
    }

    @FunctionalInterface
    private interface DataFetcher<T> {
        List<T> fetch();
    }

    public Response<String> fallbackMethod(String token, Exception e) {
        log.error("限流异常: ", e);
        return Response.<String>builder()
                .code(Constants.ErrorCode.SERVER_BUSY.getCode())
                .info(Constants.ErrorCode.SERVER_BUSY.getInfo())
                .data("服务器繁忙，请稍后再试！")
                .build();
    }
}